1584. Произвольное тасование

 

Произвольное тасование чисел массива А производится согласно следующего алгоритма:

 

n = длина массива А

for i=1 to n

 сгенерировать произвольное число r между 1 и n включительно

  поменять местами A[i] и A[r]

 

  Вычислить вероятность того, что заданный массив чисел получен в результате выполнения операции произвольного тасования набора {1, 2, …, n}. Здесь n равно количеству элементов входного массива.

 

Вход. Каждая строка является отдельным тестом и содержит значение n (1 ≤ n ≤ 10), за которым следуют элементы массива А – перестановка чисел от 1 до n.

 

Выход.  Для каждого теста в отдельной строке вывести с 4 цифрами после десятичной точки вероятность того, что входной массив получен в результате выполнения операции произвольного тасования набора {1, 2, …, n}.

 

Пример входа

1 1

2 1 2

5 4 2 5 1 3

 

Пример выхода

1.0000

0.5000

0.0067

 

 

РЕШЕНИЕ

вероятность - рекурсия - перебор

 

Анализ алгоритма

Занесем в массив cur последовательность {1, 2, …, n}. Будем моделировать все возможные процессы тасования, выбирая в качестве значения r все значения от 1 до n. Процесс тасования состоит из n итераций, на каждой из которых в качестве r можно выбрать любое из n чисел (от 1 до n). Таким образом, из последовательности {1, 2, …, n} в результате тасования можно получить nn других последовательностей, некоторые из которых возможно будут одинаковыми (nn > n!). В переменной s подсчитаем, сколько раз в процессе моделирования из {1, 2, …, n} получится последовательность, заданная в массиве outputArray.  Разделив найденное число s на nn, получим искомую вероятность.

Функция shuffle имеет единственный параметр pos – номер проводимой итерации. Для прохождения по времени следует совершить следующее отсечение. Пусть производится pos итерация, а текущий массив cur отличается от исходного m в c позициях. Тогда если c > 2*(npos), то очевидно, что за оставшиеся npos обменов невозможно из cur получить m. Это следует из того, что за каждый из оставшихся обменов мы можем переставлять максимум 2 элемента.

 

Реализация алгоритма

Объявим глобальные массивы.

 

int m[10], cur[10];

 

Реализация функции произвольного тасования.

 

void shuffle(int pos)

{

  int i, c;

  if (pos == n)

  {

    for(i = 0; i < n; i++)

      if (m[i] != cur[i]) return;

    s++;

    return;

  }

 

  for(c = i = 0; i < n; i++)

    if (m[i] != cur[i]) c++;

  if (c > 2 * (n - pos)) return;

 

  for(i = 0; i < n; i++)

  {

    swap(cur[i],cur[pos]);

    shuffle(pos + 1);

    swap(cur[i],cur[pos]);

  }

}

 

Основная часть программы.

 

while(scanf("%d",&n) == 1)

{

  for(s = i = 0; i < n; i++)

    scanf("%d",&m[i]), cur[i] = i + 1;

  shuffle(0);

  res = 1.0 * s / pow((double)n,(double)n);

  printf("%.4lf\n",res);

}